/**
 *    Copyright 2009-2016 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.type;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * 类型引用
 * 用于获取原生类型，Java中的原生类型又称为基本类型，即byte、short、int、long、float、double、boolean、char八大基本数据类型
 * References a generic type.
 *
 * @param <T> the referenced type
 * @since 3.1.0
 * @author Simone Tripodi
 */
public abstract class TypeReference<T> {

  /**
   * 引用的原生类型
   * 该类就是为了持有这个具体的类型处理器所处理的Java类型的原生类型。我们可以看到在该类中还有两个方法getRawType()和toString()方法，
   * 这两个方法都是public修饰的，是对外公开的方法， 那么也就意味着这个原生类型是为了被外部调用而设。
   */
  private final Type rawType;

  protected TypeReference() {
	//参数getClass()，这是Object类中定义的方法，这个方法返回的是当前类（实例）的类类型。
    rawType = getSuperclassTypeParameter(getClass());
  }

  Type getSuperclassTypeParameter(Class<?> clazz) {
	//得到泛型T的实际类型(class, interface, primitive type or void)
	//通过给定参数的getGenericSuperclass()方法来获取该类类型的上一级类型（直接超类，父类，即参数类类型继承的类的类型）并带有参数类型，即带泛型。如果要获取不带泛型的父类可使用getSuperclass()方法。
    Type genericSuperclass = clazz.getGenericSuperclass();
    //知识点：泛型类不是Class类的实例。因为泛型类是Java中一种独特的存在，它一般用于传递类，类似于一般方法中传递对象的概念，它不是简单的类，而是一种带有抽象概念性质的一种类，它会通过所传递的类（参数化类）来指定当前类所代表的的属于基本类型中的哪一类类型。（通过两种类型来确定具体的类型）
    if (genericSuperclass instanceof Class) {//判断获取的类型是否是Class类的实例,Class类是对Java中类的抽象，它本身也是一个类，但它是出于其他类上一层次的类，是类的顶层抽象
      // try to climb up the hierarchy until meet something useful
      //但是如果获取的genericSuperclass类型不带泛型，那么会执行下面代码，再次判断，获取的类型是否是TypeReference类型，如果不是该类型，则执行递归操作，
    	//如果是该类型，那么说明第一步通过getGenericSuperclass()获取带泛型的类型时未获取到泛型（因为MyBatis中TypeReference是泛型类），则说明程序出错，此处抛出类型异常，提示丢失泛型。
      if (TypeReference.class != genericSuperclass) {
        return getSuperclassTypeParameter(clazz.getSuperclass());
      }

      throw new TypeException("'" + getClass() + "' extends TypeReference but misses the type parameter. "
        + "Remove the extension or add a type parameter to it.");
    }
    //如果获取的genericSuperclass类型式带泛型的类型，则会执行下面代码，将该类型强转为参数化类型，使用其getActualTypeArguments()方法来获取其参数类型（泛型类型），
    //因为该方法获取的泛型类型可能不是一个，所以返回的是一个数组，但是我们这里只会获取到一个，所以取第一个即可。
    Type rawType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];
    // TODO remove this when Reflector is fixed to return Types
    //对获取的参数类型进行判断如果该类型还是参数化类型（仍然带有泛型，即泛型嵌套的模式），那么就需要再次执行getActualTypeArguments()方法来获取其泛型类型（参数类型），
    //最后将该类型返回（赋值给字段）
    //为什么只会获取两次呢？因为，通过之前的类架构我们已经明白，具体的类型处理器最多只会存在两层继承。
    if (rawType instanceof ParameterizedType) {
      rawType = ((ParameterizedType) rawType).getRawType();
    }

    return rawType;
  }

  public final Type getRawType() {
    return rawType;
  }

  @Override
  public String toString() {
    return rawType.toString();
  }

}
